// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_auth_handler.h"

#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/logging.h"
#include "net/base/net_errors.h"
#include "net/http/http_auth_challenge_tokenizer.h"

namespace net {

HttpAuthHandler::HttpAuthHandler()
    : auth_scheme_(HttpAuth::AUTH_SCHEME_MAX)
    , score_(-1)
    , target_(HttpAuth::AUTH_NONE)
    , properties_(-1)
{
}

HttpAuthHandler::~HttpAuthHandler()
{
}

bool HttpAuthHandler::InitFromChallenge(HttpAuthChallengeTokenizer* challenge,
    HttpAuth::Target target,
    const SSLInfo& ssl_info,
    const GURL& origin,
    const BoundNetLog& net_log)
{
    origin_ = origin;
    target_ = target;
    score_ = -1;
    properties_ = -1;
    net_log_ = net_log;

    auth_challenge_ = challenge->challenge_text();
    bool ok = Init(challenge, ssl_info);

    // Init() is expected to set the scheme, realm, score, and properties.  The
    // realm may be empty.
    DCHECK(!ok || score_ != -1);
    DCHECK(!ok || properties_ != -1);
    DCHECK(!ok || auth_scheme_ != HttpAuth::AUTH_SCHEME_MAX);

    return ok;
}

namespace {

    NetLog::EventType EventTypeFromAuthTarget(HttpAuth::Target target)
    {
        switch (target) {
        case HttpAuth::AUTH_PROXY:
            return NetLog::TYPE_AUTH_PROXY;
        case HttpAuth::AUTH_SERVER:
            return NetLog::TYPE_AUTH_SERVER;
        default:
            NOTREACHED();
            return NetLog::TYPE_CANCELLED;
        }
    }

} // namespace

int HttpAuthHandler::GenerateAuthToken(
    const AuthCredentials* credentials, const HttpRequestInfo* request,
    const CompletionCallback& callback, std::string* auth_token)
{
    DCHECK(!callback.is_null());
    DCHECK(request);
    DCHECK(credentials != NULL || AllowsDefaultCredentials());
    DCHECK(auth_token != NULL);
    DCHECK(callback_.is_null());
    callback_ = callback;
    net_log_.BeginEvent(EventTypeFromAuthTarget(target_));
    int rv = GenerateAuthTokenImpl(
        credentials, request,
        base::Bind(&HttpAuthHandler::OnGenerateAuthTokenComplete,
            base::Unretained(this)),
        auth_token);
    if (rv != ERR_IO_PENDING)
        FinishGenerateAuthToken();
    return rv;
}

bool HttpAuthHandler::NeedsIdentity()
{
    return true;
}

bool HttpAuthHandler::AllowsDefaultCredentials()
{
    return false;
}

bool HttpAuthHandler::AllowsExplicitCredentials()
{
    return true;
}

void HttpAuthHandler::OnGenerateAuthTokenComplete(int rv)
{
    CompletionCallback callback = callback_;
    FinishGenerateAuthToken();
    DCHECK(!callback.is_null());
    callback.Run(rv);
}

void HttpAuthHandler::FinishGenerateAuthToken()
{
    // TOOD(cbentzel): Should this be done in OK case only?
    net_log_.EndEvent(EventTypeFromAuthTarget(target_));
    callback_.Reset();
}

} // namespace net
